home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / GLUT / progs / examples / zoomdino.c < prev   
C/C++ Source or Header  |  1996-11-11  |  13KB  |  467 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994.  */
  3.  
  4. /* This program is freely distributable without licensing fees 
  5.    and is provided without guarantee or warrantee expressed or 
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. /* zoomdino demonstrates GLUT 3.0's new overlay support.  Both
  9.    rubber-banding the display of a help message use the overlays. */
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <math.h>       /* for cos(), sin(), and sqrt() */
  15. #include <GL/glu.h>
  16. #include <GL/glut.h>
  17.  
  18. typedef enum {
  19.   RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
  20.   LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
  21. } displayLists;
  22.  
  23. GLfloat angle = -150;   /* in degrees */
  24. GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
  25. int moving, begin;
  26. int W = 300, H = 300;
  27. GLdouble bodyWidth = 2.0;
  28. int newModel = 1;
  29. /* *INDENT-OFF* */
  30. GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
  31.   {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
  32.   {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
  33.   {1, 2} };
  34. GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
  35.   {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
  36.   {13, 9}, {11, 11}, {9, 11} };
  37. GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
  38.   {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
  39. GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
  40.   {9.6, 15.25}, {9, 15.25} };
  41. GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
  42. GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
  43. GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
  44. GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0}; /* red-tinted */
  45. GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
  46. int overlaySupport, red, white, transparent, rubberbanding;
  47. int anchorx, anchory, stretchx, stretchy, pstretchx, pstretchy;
  48. float vx, vy, vx2, vy2, vw, vh;
  49. float wx, wy, wx2, wy2, ww, wh;
  50. int fancy, wasFancy, help, clearHelp;
  51. /* *INDENT-ON* */
  52.  
  53. void
  54. extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
  55.   GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
  56. {
  57.   static GLUtriangulatorObj *tobj = NULL;
  58.   GLdouble vertex[3], dx, dy, len;
  59.   int i;
  60.   int count = dataSize / (2 * sizeof(GLfloat));
  61.  
  62.   if (tobj == NULL) {
  63.     tobj = gluNewTess();  /* create and initialize a GLU
  64.                              polygontesselation object */
  65.     gluTessCallback(tobj, GLU_BEGIN, glBegin);
  66.     gluTessCallback(tobj, GLU_VERTEX, glVertex2fv);  /* semi-tricky 
  67.  
  68.                                                       */
  69.     gluTessCallback(tobj, GLU_END, glEnd);
  70.   }
  71.   glNewList(side, GL_COMPILE);
  72.   glShadeModel(GL_SMOOTH);  /* smooth minimizes seeing
  73.                                tessellation */
  74.   gluBeginPolygon(tobj);
  75.   for (i = 0; i < count; i++) {
  76.     vertex[0] = data[i][0];
  77.     vertex[1] = data[i][1];
  78.     vertex[2] = 0;
  79.     gluTessVertex(tobj, vertex, data[i]);
  80.   }
  81.   gluEndPolygon(tobj);
  82.   glEndList();
  83.   glNewList(edge, GL_COMPILE);
  84.   glShadeModel(GL_FLAT);  /* flat shade keeps angular hands
  85.                              from being "smoothed" */
  86.   glBegin(GL_QUAD_STRIP);
  87.   for (i = 0; i <= count; i++) {
  88.     /* mod function handles closing the edge */
  89.     glVertex3f(data[i % count][0], data[i % count][1], 0.0);
  90.     glVertex3f(data[i % count][0], data[i % count][1], thickness);
  91.  
  92.     /* Calculate a unit normal by dividing by Euclidean
  93.        distance. We could be lazy and use
  94.        glEnable(GL_NORMALIZE) so we could pass in arbitrary
  95.        normals for a very slight performance hit. */
  96.  
  97.     dx = data[(i + 1) % count][1] - data[i % count][1];
  98.     dy = data[i % count][0] - data[(i + 1) % count][0];
  99.     len = sqrt(dx * dx + dy * dy);
  100.     glNormal3f(dx / len, dy / len, 0.0);
  101.   }
  102.   glEnd();
  103.   glEndList();
  104.   glNewList(whole, GL_COMPILE);
  105.   glFrontFace(GL_CW);
  106.   glCallList(edge);
  107.   glNormal3f(0.0, 0.0, -1.0);  /* constant normal for side */
  108.   glCallList(side);
  109.   glPushMatrix();
  110.   glTranslatef(0.0, 0.0, thickness);
  111.   glFrontFace(GL_CCW);
  112.   glNormal3f(0.0, 0.0, 1.0);  /* opposite normal for other side */
  113.   glCallList(side);
  114.   glPopMatrix();
  115.   glEndList();
  116. }
  117.  
  118. void
  119. makeDinosaur(void)
  120. {
  121.   GLfloat bodyWidth = 3.0;
  122.  
  123.   extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
  124.     BODY_SIDE, BODY_EDGE, BODY_WHOLE);
  125.   extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
  126.     ARM_SIDE, ARM_EDGE, ARM_WHOLE);
  127.   extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
  128.     LEG_SIDE, LEG_EDGE, LEG_WHOLE);
  129.   extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
  130.     EYE_SIDE, EYE_EDGE, EYE_WHOLE);
  131.   glNewList(DINOSAUR, GL_COMPILE);
  132.   glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
  133.   glCallList(BODY_WHOLE);
  134.   glPushMatrix();
  135.   glTranslatef(0.0, 0.0, bodyWidth);
  136.   glCallList(ARM_WHOLE);
  137.   glCallList(LEG_WHOLE);
  138.   glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
  139.   glCallList(ARM_WHOLE);
  140.   glTranslatef(0.0, 0.0, -bodyWidth / 4);
  141.   glCallList(LEG_WHOLE);
  142.   glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
  143.   glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
  144.   glCallList(EYE_WHOLE);
  145.   glPopMatrix();
  146.   glEndList();
  147. }
  148.  
  149. void
  150. recalcModelView(void)
  151. {
  152.   glPopMatrix();
  153.   glPushMatrix();
  154.   glRotatef(angle, 0.0, 1.0, 0.0);
  155.   glTranslatef(-8, -8, -bodyWidth / 2);
  156.   newModel = 0;
  157. }
  158.  
  159. void
  160. redraw(void)
  161. {
  162.   if (newModel)
  163.     recalcModelView();
  164.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  165.   glCallList(DINOSAUR);
  166.   glutSwapBuffers();
  167. }
  168.  
  169. void
  170. output(int x, int y, char *string)
  171. {
  172.   int len, i;
  173.  
  174.   glRasterPos2f(x, y);
  175.   len = (int) strlen(string);
  176.   for (i = 0; i < len; i++) {
  177.     glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, string[i]);
  178.   }
  179. }
  180.  
  181. char *helpMsg[] =
  182. {
  183.   "Welcome to zoomdino!",
  184.   "   Left mouse button rotates",
  185.   "     the dinosaur.",
  186.   "   Middle mouse button zooms",
  187.   "     via overlay rubber-banding.",
  188.   "   Right mouse button shows",
  189.   "     pop-up menu.",
  190.   "   To reset view, use \"Reset",
  191.   "     Projection\".",
  192.   "(This message is in the overlays.)",
  193.   NULL
  194. };
  195.  
  196. void
  197. redrawOverlay(void)
  198. {
  199.   if (help) {
  200.     int i;
  201.  
  202.     glClear(GL_COLOR_BUFFER_BIT);
  203.     glIndexi(white);
  204.     for (i = 0; helpMsg[i]; i++) {
  205.       output(15, 24 + i * 18, helpMsg[i]);
  206.     }
  207.     return;
  208.   }
  209.   if (glutLayerGet(GLUT_OVERLAY_DAMAGED) || clearHelp) {
  210.     /* Opps, damage means we need a full clear. */
  211.     glClear(GL_COLOR_BUFFER_BIT);
  212.     clearHelp = 0;
  213.     wasFancy = 0;
  214.   } else {
  215.     /* Goody!  No damage.  Just erase last rubber-band. */
  216.     if (fancy || wasFancy) {
  217.       glLineWidth(3.0);
  218.     }
  219.     glIndexi(transparent);
  220.     glBegin(GL_LINE_LOOP);
  221.     glVertex2i(anchorx, anchory);
  222.     glVertex2i(anchorx, pstretchy);
  223.     glVertex2i(pstretchx, pstretchy);
  224.     glVertex2i(pstretchx, anchory);
  225.     glEnd();
  226.   }
  227.   if (wasFancy) {
  228.     glLineWidth(1.0);
  229.     wasFancy = 0;
  230.   }
  231.   if (fancy)
  232.     glLineWidth(3.0);
  233.   glIndexi(red);
  234.   glBegin(GL_LINE_LOOP);
  235.   glVertex2i(anchorx, anchory);
  236.   glVertex2i(anchorx, stretchy);
  237.   glVertex2i(stretchx, stretchy);
  238.   glVertex2i(stretchx, anchory);
  239.   glEnd();
  240.   if (fancy) {
  241.     glLineWidth(1.0);
  242.     glIndexi(white);
  243.     glBegin(GL_LINE_LOOP);
  244.     glVertex2i(anchorx, anchory);
  245.     glVertex2i(anchorx, stretchy);
  246.     glVertex2i(stretchx, stretchy);
  247.     glVertex2i(stretchx, anchory);
  248.     glEnd();
  249.   }
  250.   glFlush();
  251.  
  252.   /* Remember last place rubber-banded so the rubber-band can
  253.      be erased next redisplay. */
  254.   pstretchx = stretchx;
  255.   pstretchy = stretchy;
  256. }
  257.  
  258. void
  259. defaultProjection(void)
  260. {
  261.   glMatrixMode(GL_PROJECTION);
  262.   glLoadIdentity();
  263.   vx = -1.0;
  264.   vw = 2.0;
  265.   vy = -1.0;
  266.   vh = 2.0;
  267.   glFrustum(vx, vx + vw, vy, vy + vh, 1.0, 40);
  268.   glMatrixMode(GL_MODELVIEW);
  269. }
  270.  
  271. void
  272. mouse(int button, int state, int x, int y)
  273. {
  274.   if (button == GLUT_LEFT_BUTTON) {
  275.     if (state == GLUT_DOWN) {
  276.       glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
  277.       moving = 1;
  278.       begin = x;
  279.     } else if (state == GLUT_UP) {
  280.       glutSetCursor(GLUT_CURSOR_INHERIT);
  281.       moving = 0;
  282.     }
  283.   }
  284.   if (overlaySupport && button == GLUT_MIDDLE_BUTTON) {
  285.     if (state == GLUT_DOWN) {
  286.       help = 0;
  287.       clearHelp = 1;
  288.       rubberbanding = 1;
  289.       anchorx = x;
  290.       anchory = y;
  291.       stretchx = x;
  292.       stretchy = y;
  293.       glutShowOverlay();
  294.     } else if (state == GLUT_UP) {
  295.       rubberbanding = 0;
  296.       glutHideOverlay();
  297.       glutUseLayer(GLUT_NORMAL);
  298.       glMatrixMode(GL_PROJECTION);
  299.       glLoadIdentity();
  300.  
  301. #define max(a,b)  ((a) > (b) ? (a) : (b))
  302. #define min(a,b)  ((a) < (b) ? (a) : (b))
  303.  
  304.       wx = min(anchorx, stretchx);
  305.       wy = min(H - anchory, H - stretchy);
  306.       wx2 = max(anchorx, stretchx);
  307.       wy2 = max(H - anchory, H - stretchy);
  308.       ww = wx2 - wx;
  309.       wh = wy2 - wy;
  310.       if (ww == 0 || wh == 0) {
  311.         glutUseLayer(GLUT_NORMAL);
  312.         defaultProjection();
  313.       } else {
  314.  
  315.         vx2 = wx2 / W * vw + vx;
  316.         vx = wx / W * vw + vx;
  317.         vy2 = wy2 / H * vh + vy;
  318.         vy = wy / H * vh + vy;
  319.         vw = vx2 - vx;
  320.         vh = vy2 - vy;
  321.  
  322.         glFrustum(vx, vx + vw, vy, vy + vh, 1.0, 40);
  323.       }
  324.       glutPostRedisplay();
  325.       glMatrixMode(GL_MODELVIEW);
  326.     }
  327.   }
  328. }
  329.  
  330. void
  331. motion(int x, int y)
  332. {
  333.   if (moving) {
  334.     angle = angle + (x - begin);
  335.     begin = x;
  336.     newModel = 1;
  337.     glutPostRedisplay();
  338.   }
  339.   if (rubberbanding) {
  340.     stretchx = x;
  341.     stretchy = y;
  342.     glutPostOverlayRedisplay();
  343.   }
  344. }
  345.  
  346. void
  347. reshape(int w, int h)
  348. {
  349.   if (overlaySupport) {
  350.     glutUseLayer(GLUT_OVERLAY);
  351.     glViewport(0, 0, w, h);
  352.     glMatrixMode(GL_PROJECTION);
  353.     glLoadIdentity();
  354.     gluOrtho2D(0, w, 0, h);
  355.     glScalef(1, -1, 1);
  356.     glTranslatef(0, -h, 0);
  357.     glMatrixMode(GL_MODELVIEW);
  358.     glutUseLayer(GLUT_NORMAL);
  359.   }
  360.   glViewport(0, 0, w, h);
  361.   W = w;
  362.   H = h;
  363. }
  364.  
  365. GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
  366.  
  367. void
  368. controlLights(int value)
  369. {
  370.   glutUseLayer(GLUT_NORMAL);
  371.   switch (value) {
  372.   case 1:
  373.     lightZeroSwitch = !lightZeroSwitch;
  374.     if (lightZeroSwitch) {
  375.       glEnable(GL_LIGHT0);
  376.     } else {
  377.       glDisable(GL_LIGHT0);
  378.     }
  379.     break;
  380.   case 2:
  381.     lightOneSwitch = !lightOneSwitch;
  382.     if (lightOneSwitch) {
  383.       glEnable(GL_LIGHT1);
  384.     } else {
  385.       glDisable(GL_LIGHT1);
  386.     }
  387.     break;
  388.   case 3:
  389.     defaultProjection();
  390.     break;
  391.   case 4:
  392.     fancy = 1;
  393.     break;
  394.   case 5:
  395.     fancy = 0;
  396.     wasFancy = 1;
  397.     break;
  398.   case 6:
  399.     if (!rubberbanding)
  400.       help = 1;
  401.     glutShowOverlay();
  402.     glutPostOverlayRedisplay();
  403.     break;
  404.   }
  405.   glutPostRedisplay();
  406. }
  407.  
  408. int
  409. main(int argc, char **argv)
  410. {
  411.   glutInit(&argc, argv);
  412.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  413.   glutCreateWindow("zoomdino");
  414.   glutDisplayFunc(redraw);
  415.   glutMouseFunc(mouse);
  416.   glutMotionFunc(motion);
  417.   glutCreateMenu(controlLights);
  418.   glutAddMenuEntry("Toggle right light", 1);
  419.   glutAddMenuEntry("Toggle left light", 2);
  420.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  421.   makeDinosaur();
  422.   glEnable(GL_CULL_FACE);
  423.   glEnable(GL_DEPTH_TEST);
  424.   glEnable(GL_LIGHTING);
  425.   defaultProjection();
  426.   gluLookAt(0.0, 0.0, 30.0,  /* eye is at (0,0,30) */
  427.     0.0, 0.0, 0.0,      /* center is at (0,0,0) */
  428.     0.0, 1.0, 0.);      /* up is in postivie Y direction */
  429.   glPushMatrix();       /* dummy push so we can pop on model
  430.                            recalc */
  431.   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  432.   glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
  433.   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
  434.   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
  435.   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
  436.   glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
  437.   glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
  438.   glEnable(GL_LIGHT0);
  439.   glEnable(GL_LIGHT1);
  440.   glutInitDisplayMode(GLUT_SINGLE | GLUT_INDEX);
  441.   overlaySupport = glutLayerGet(GLUT_OVERLAY_POSSIBLE);
  442.   if (overlaySupport) {
  443.     glutEstablishOverlay();
  444.     glutHideOverlay();
  445.     transparent = glutLayerGet(GLUT_TRANSPARENT_INDEX);
  446.     glClearIndex(transparent);
  447.     red = (transparent + 1) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
  448.     white = (transparent + 2) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
  449.     glutSetColor(red, 1.0, 0.0, 0.0);  /* Red. */
  450.     glutSetColor(white, 1.0, 1.0, 1.0);  /* White. */
  451.     glutOverlayDisplayFunc(redrawOverlay);
  452.     glutReshapeFunc(reshape);
  453.     glutSetWindowTitle("zoomdino with rubber-banding");
  454.     glutAddMenuEntry("------------------", 0);
  455.     glutAddMenuEntry("Reset projection", 3);
  456.     glutAddMenuEntry("------------------", 0);
  457.     glutAddMenuEntry("Fancy rubber-banding", 4);
  458.     glutAddMenuEntry("Simple rubber-banding", 5);
  459.     glutAddMenuEntry("------------------", 0);
  460.     glutAddMenuEntry("Show help", 6);
  461.   } else {
  462.     printf("Sorry, no whizzy zoomdino overlay usage!\n");
  463.   }
  464.   glutMainLoop();
  465.   return 0;             /* ANSI C requires main to return int. */
  466. }
  467.